﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;

namespace ZZT
{
    abstract public class Board
    {
        virtual public int CameraX { get; set; }
        virtual public int CameraY { get; set; }
        virtual public bool Dark { get; set; }
        virtual public int ExitEast { get; set; }
        virtual public int ExitNorth { get; set; }
        virtual public int ExitSouth { get; set; }
        virtual public int ExitWest { get; set; }
        virtual public int MaximumShots { get; set; }
        virtual public string Message { get; set; }
        virtual public string Name { get; set; }
        virtual public int PlayerEnterX { get; set; }
        virtual public int PlayerEnterY { get; set; }
        virtual public bool RestartOnZap { get; set; }
        virtual public int TimeLimit { get; set; }

        abstract public Tile this[int index] { get; }
        abstract public Tile this[Point point] { get; }
        abstract public Tile EdgeTile { get; }
        abstract public int Height { get; }
        abstract public int NameLength { get; }
        abstract public void Pack(Stream target);
        abstract public void UnPack(Stream source);
        abstract public int Width { get; }

        public Board()
        {
            // initialize edge tiles
            for (int x = 0; x < WidthTotal; x++)
            {
                EdgeTile.CopyTo(this[new Point(x, 0)]);
                EdgeTile.CopyTo(this[new Point(x, HeightTotal - 1)]);
            }
            for (int y = 0; y < HeightTotal; y++)
            {
                EdgeTile.CopyTo(this[new Point(0, y)]);
                EdgeTile.CopyTo(this[new Point(WidthTotal - 1, y)]);
            }
        }

        protected void CompressRLE(Stream target)
        {
            int startX = 1;
            int startY = 1;
            int endX = WidthTotal - 2;
            int endY = HeightTotal - 2;

            Tile tile = this[new Point(startX, startY)];
            int id = tile.Id;
            int color = tile.Color;
            int count = 1;
            startX++;

            for (int y = startY; y < endY; y++)
            {
                for (int x = startX; x < endX; x++)
                {
                    tile = this[new Point(startX, startY)];
                    if (id != tile.Id || color != tile.Color || count == 255)
                    {
                        target.WriteByte((byte)(count & 0xFF));
                        target.WriteByte((byte)(id & 0xFF));
                        target.WriteByte((byte)(color & 0xFF));
                        count = 0;
                        id = tile.Id;
                        color = tile.Color;
                    }
                    count++;
                }
            }

            target.WriteByte((byte)(count & 0xFF));
            target.WriteByte((byte)(id & 0xFF));
            target.WriteByte((byte)(color & 0xFF));
        }

        protected void DecompressRLE(Stream source)
        {
            int x = 1;
            int y = 1;
            int count = 0;
            byte[] data = new byte[3];
            Tile tile = new Tile(data, 1);

            while (y < HeightTotal - 2)
            {
                source.Read(data, 0, 3);
                count = data[0];
                if (count == 0)
                {
                    count = 256;
                }
                while (count > 0)
                {
                    tile.CopyTo(this[new Point(x, y)]);
                    x++;
                    if (x >= WidthTotal - 2)
                    {
                        x = 1;
                        y++;
                    }
                }
            }
        }

        public int HeightTotal
        {
            get { return Height + 2; }
        }

        public int WidthTotal
        {
            get { return Width + 2; }
        }
    }
}
